| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- 'use client';
- import { useCallback, useState } from 'react';
- import { fetchApi } from '@/lib/utils/client';
- import { FeedReply, FeedRepliesResponse } from '@/types/feed/post';
- import FeedReplyItem from './FeedReplyItem';
- type Props = {
- postID: number;
- initialReplies: FeedReply[];
- initialTotal: number;
- onReply: (target: FeedReply) => void;
- refreshKey: number;
- };
- const PER_PAGE = 30;
- export default function FeedReplyList({ postID, initialReplies, initialTotal, onReply, refreshKey }: Props) {
- const [replies, setReplies] = useState<FeedReply[]>(initialReplies);
- const [total, setTotal] = useState<number>(initialTotal);
- const [page, setPage] = useState<number>(2);
- const [loading, setLoading] = useState<boolean>(false);
- const [lastRefreshKey, setLastRefreshKey] = useState<number>(refreshKey);
- const loadMore = useCallback(async () => {
- if (loading) {
- return;
- }
- setLoading(true);
- try {
- const res = await fetchApi<FeedRepliesResponse>(`/api/feed/post/${postID}/replies?page=${page}&perPage=${PER_PAGE}`, {
- method: 'GET',
- silent: true
- });
- const list = res.data?.list ?? [];
- setReplies((prev) => {
- const seen = new Set(prev.map((r) => r.id));
- const dedup = list.filter((r) => !seen.has(r.id));
- return [...prev, ...dedup];
- });
- setTotal(res.data?.total ?? total);
- setPage((p) => p + 1);
- } catch (err) {
- console.error(err);
- } finally {
- setLoading(false);
- }
- }, [loading, postID, page, total]);
- const reload = useCallback(async () => {
- setLoading(true);
- try {
- const res = await fetchApi<FeedRepliesResponse>(`/api/feed/post/${postID}/replies?page=1&perPage=${PER_PAGE}`, {
- method: 'GET',
- silent: true
- });
- setReplies(res.data?.list ?? []);
- setTotal(res.data?.total ?? 0);
- setPage(2);
- } catch (err) {
- console.error(err);
- } finally {
- setLoading(false);
- }
- }, [postID]);
- if (refreshKey !== lastRefreshKey) {
- setLastRefreshKey(refreshKey);
- reload();
- }
- const handleDelete = (id: number) => {
- setReplies((prev) => prev.map(r => r.id === id ? { ...r, isDeleted: true, content: '' } : r));
- };
- if (replies.length === 0) {
- return <p className="feed__reply-empty">아직 답글이 없습니다. 첫 답글을 남겨보세요.</p>;
- }
- const hasMore = replies.length < total;
- return (
- <div className="feed__reply-list" role="feed">
- <div className="feed__reply-count">답글 {total.toLocaleString()}개</div>
- {replies.map((reply) => (
- <FeedReplyItem
- key={reply.id}
- reply={reply}
- onReply={onReply}
- onDelete={handleDelete}
- />
- ))}
- {hasMore && (
- <button type="button" className="feed__reply-more-btn" onClick={loadMore} disabled={loading}>
- {loading ? '불러오는 중...' : '답글 더 보기'}
- </button>
- )}
- </div>
- );
- }
|